#include "SubsystemBedWarsTerrain.h"
#include "TerrainContentsGeneratorBedWars.h"
#include "ServerConfigure.h"
// #include "TerrainSerializerBedWars.h"
#include "GameConstans.h"
#include "Managers/GameManager.h"
#include "BedWars.h"
#include "Log.h"
// #include "Terrain/TerrainUpdater.h"
#include "TerrainUpdaterBedWars.h"
#include "GameThreadPool.hpp"

using namespace PocketSurvival;

namespace BedWars
{
    SubsystemBedWarsTerrain::SubsystemBedWarsTerrain(){}


    void SubsystemBedWarsTerrain::discardTerrainModify(std::vector<Point2> &discardChunkVec)
    {
        m_chunkMapMutex.lock();

        std::map<Point2, TerrainChunk*> chunkMapCatch;

        for(auto &pair : m_chunkMap)
        {
            if(pair.second->isChange == true)
            {
                // 放入缓存队列，重复利用

                discardChunkVec.push_back(pair.first);
                if(m_chunkQueue.enqueue(pair.second) == false)
                {
                    Log::Error("[bedwars]回收TerrainChunk失败");
                }
                // pair.second->isRemove = true;
            }
            else
            {
                // if(m_chunkQueue.enqueue(pair.second) == false)
                // {
                //     Log::error("[bedwars]回收TerrainChunk失败");
                // }
                // chunkMapCatch[pair.first] = pair.second;
                chunkMapCatch.emplace(pair.first, pair.second);
            }
        }

        m_chunkMap.swap(chunkMapCatch);
        // m_chunkMap.clear();
        // std::swap(m_chunkMap, chunkMapCatch);

        m_chunkMapMutex.unlock();
    }

    void SubsystemBedWarsTerrain::update(float dt)
    {
        processModifiedCells();

        // 若要回收的区块出现在加载中的话，那么就不需要回收处理了
        m_loadChunkMutex.lock();
        for(auto it = m_loadChunkSet.begin(); it != m_loadChunkSet.end(); ++it)
        {
            auto chunkMapIt = m_chunkMap.find(*it);
            if(chunkMapIt != m_chunkMap.end())
            {
                chunkMapIt->second->recycleTime = 0.0f;
                chunkMapIt->second->isRemove = false;
            }
        }
        m_loadChunkMutex.unlock();
        
        // 回收区块
        m_chunkMapMutex.lock();
        std::vector<Point2> remveChunkVec;
        for(auto it = m_chunkMap.cbegin(); it != m_chunkMap.cend(); ++it)
        {
            if(it->second->isRemove == true)
            {
                remveChunkVec.push_back(it->first);
            }
        }
        
        int32_t num = 0;
        for(auto it = remveChunkVec.cbegin(); it != remveChunkVec.cend(); ++it)
        {
            auto chunkMapIt = m_chunkMap.find(*it);
            TerrainChunk *terrainChunk = chunkMapIt->second;
            
            // 区块有改变的话，则需要保存处理
            // if(terrainChunk->isChange == true)
            // {
            //     m_threadPool->push_task([terrainChunk,this]
            //     {
            //         terrainSerializer->saveChunk(terrainChunk);
            //         m_chunkQueue.enqueue(terrainChunk);
            //     });
            // }
            // else
            {
                m_chunkQueue.enqueue(terrainChunk);
            }
            m_chunkMap.erase(chunkMapIt);
            num++;
        }

        m_chunkMapMutex.unlock();

        // 只有将需要回收的区块回收处理完后才能调用地形刷新和后面的地形生成
        terrainUpdater->update(dt);

        // 地形保存处理
        if(bedWaresCore->isEditMode == true)
        {
            m_saveRegionTime += dt;
            if ((int32_t)m_saveRegionTime % 120 == 0)
            {
                saveAllChunk();
            }
            else if(m_saveRegionTime > 300.0f && num == 0)
            {
                m_saveRegionTime = 0.0f;
                terrainSerializer->saveAndReleaseAllRegion();
                return;
            }
        }

        // 加载区块
        std::lock_guard<std::mutex> lk(m_loadChunkMutex);

        // 快速加载，不过一次性加载这么多，可能会卡到总体的进度，就是tick的处理时间
        for (auto it = m_loadChunkSet.begin(); it != m_loadChunkSet.end(); ++it)
        {
            if(m_chunkMap.find(*it) == m_chunkMap.end())
            {
                TerrainChunk *terrainChunk = this->getAvailableChunk(it->posX, it->posY);
                if (terrainChunk != nullptr)
                {
                    m_chunkMapMutex.lock();
                    m_chunkMap[*it] = terrainChunk;
                    m_chunkMapMutex.unlock();
                    m_threadPool->push_task(&TerrainUpdater::loadChunk, terrainUpdater.get(), terrainChunk);
                }
            }
        }
        m_loadChunkSet.clear();
    }

    void SubsystemBedWarsTerrain::load(const nlohmann::json &json)
    {
        SubsystemTerrain::load(json);
        m_serverConfigure->terrainChunkRecycleTime = 10.0f;
        terrainContentsGenerator = std::make_shared<TerrainContentsGeneratorBedWars>();
        terrainUpdater = std::make_shared<TerrainUpdaterBedWars>();
    }

    void SubsystemBedWarsTerrain::save(nlohmann::json &json)
    {
        if(bedWaresCore->isEditMode == true)
        {
            saveAllChunk();
            m_threadPool->wait_for_tasks();
            terrainSerializer->saveAllRegion();
        }
    }

}